home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvitops / special.c < prev    next >
C/C++ Source or Header  |  1991-01-25  |  23KB  |  1,051 lines

  1. static char rcsid[] = "$Header: /usr/jjc/dvitops/RCS/special.c,v 1.9 90/08/14 13:56:04 jjc Rel $";
  2.  
  3. #include "dvitops.h"
  4.  
  5. struct bounding_box { double llx, lly, urx, ury; };
  6.  
  7. #ifdef PROTO
  8. static void do_import(char *arg, integer x, integer y,
  9.     int region, struct page_info *page, FILE *psfp);
  10. int strprefix(char *prefix, char *s);
  11. static void read_import_file(char *filename);
  12. #else
  13. static void do_import();
  14. int strprefix();
  15. static void read_import_file();
  16. #endif
  17.  
  18. /* this holds the list of files to be imported on the current page */
  19. static struct import {
  20.     integer x, y;
  21.     int region;
  22.     struct import *next;
  23.     char arg[1];
  24. } *import_list;
  25.  
  26.  
  27. static struct import_file {
  28.     struct bounding_box bb;
  29.     struct depend_list *font;
  30.     struct import_file *next;
  31.     char file[1];
  32. } *doc_import_list;
  33.  
  34. /* this routine is used to include a PostScript file
  35. it will be enhanced later to be quicker and possibly to support
  36. %%IncludeFont and %%IncludeFile comments 
  37. return 0 on success, -1 on error
  38. */
  39.  
  40. int include_file(filename, psfp)
  41. char *filename;
  42. FILE *psfp;
  43. {
  44.     char buf[256];
  45.     FILE *infp;
  46.     if ((infp = xfopen(filename, FALSE, texinputs, (char *)NULL)) == NULL)
  47.         return EOF;
  48. #ifdef HAVE_SETVBUF
  49.     setvbuf(infp, (char *)NULL, _IOFBF, 16384);
  50. #endif
  51.     while (fgets(buf, sizeof(buf), infp) != NULL)
  52.         if (buf[0] != '%')
  53.             fputs(buf, psfp);
  54.     fclose(infp);
  55.     return 0;
  56. }
  57.  
  58. /* return 0 on error */
  59.  
  60. int bigpoint(str, ptr, val)
  61. char *str, **ptr;
  62. double *val;
  63. {
  64.     double x;
  65.     int n;
  66.     while (isspace(*str))
  67.         ++str;
  68.     if (sscanf(str, "%lf", &x) != 1)
  69.         goto bad;
  70.     while (isdigit(*str) || *str == '.')
  71.         str++;
  72.     while (isspace(*str))
  73.         str++;
  74.     n = isupper(str[0]) ? tolower(str[0]) : str[0];
  75.     n <<= 8;
  76.     n |= isupper(str[1]) ? tolower(str[1]) : str[1];
  77.     switch (n) {
  78.     case ('b' << 8) + 'p' :
  79.         break;
  80.     case ('i' << 8) + 'n' :
  81.         x *= 72.0;
  82.         break;
  83.     case ('c' << 8) + 'm' :
  84.         x *= 72.0/2.54;
  85.         break;
  86.     case ('m' << 8) + 'm' :
  87.         x *= 72.0/25.4;
  88.         break;
  89.     case ('s' << 8) + 'p' :
  90.         x *= 72.0/(72.27*65536.0);
  91.         break;
  92.     case ('c' << 8) + 'c' :
  93.         x *= 12.0*1238.0*72.0/(1157.0*72.27);
  94.         break;
  95.     case ('d' << 8) + 'd' :
  96.         x *= 1238.0*72.0/(1157.0*72.27);
  97.         break;
  98.     case ('p' << 8) + 't' :
  99.         x *= 72.0/72.27;
  100.         break;
  101.     case ('p' << 8) + 'c' :
  102.         x *= 12.0*72.0/72.27;
  103.         break;
  104.     default:
  105.         goto bad;
  106.     }
  107.     str += 2;
  108.     if (ptr != NULL)
  109.         *ptr = str;
  110.     *val = x;
  111.     return 1;
  112. bad:
  113.     if (ptr != NULL)
  114.         *ptr = str;
  115.     return 0;
  116. }
  117.  
  118. static void do_import(arg, x, y, region, page, psfp)
  119. char *arg;
  120. integer x, y;
  121. int region;
  122. struct page_info *page;
  123. FILE *psfp;
  124. {
  125.     double xscale, yscale;
  126.     integer gap;
  127.     double h, w;
  128.     integer width, height;
  129.     char *filename;
  130.     struct import_file *p;
  131.     struct depend_list *q;
  132.     struct bounding_box bb;
  133.     integer llx, lly, urx, ury;
  134.     double sf = (double)page->den*254000.0/((double)page->num*72.0);
  135.     char *ptr = arg;
  136.     typedef enum { CENTER, LEFT, RIGHT, TOP, BOTTOM, FILL } adjust_t;
  137.     adjust_t hadj = CENTER, vadj = CENTER;
  138.     while (isspace(*ptr))
  139.         ptr++;
  140.     filename = ptr;
  141.     while (!isspace(*ptr) && *ptr != '\0')
  142.         ptr++;
  143.     if (*ptr == '\0') {
  144.         message(ERROR, "import \\special syntax error: abandoning import");
  145.         return;
  146.     }
  147.     *ptr++ = '\0';
  148.     if (bigpoint(ptr, &ptr, &w) == 0
  149.             || bigpoint(ptr, &ptr, &h) == 0) {
  150.         message(ERROR, "special import syntax error: abandoning import");
  151.         return;
  152.     }
  153.     ptr = strtok(ptr, "\r\n\t ");
  154.     while (ptr != NULL) {
  155.         int i;
  156.         for (i = 0; ptr[i] != '\0'; i++)
  157.             ptr[i] = isupper(ptr[i]) ? tolower(ptr[i]) : ptr[i];
  158.         if (strcmp(ptr, "top") == 0)
  159.             vadj = TOP;
  160.         else if (strcmp(ptr, "bottom") == 0)
  161.             vadj = BOTTOM;
  162.         else if (strcmp(ptr, "fill") == 0)
  163.             hadj = vadj = FILL;
  164.         else if (strcmp(ptr, "left") == 0)
  165.             hadj = LEFT;
  166.         else if (strcmp(ptr, "right") == 0)
  167.             hadj = RIGHT;
  168.         else
  169.             message(ERROR, "bad option in import \\special: %s: ignored",ptr);
  170.         ptr = strtok((char *)NULL, " \r\n\t");
  171.     }
  172.     /* convert to dvi units */
  173.     width = (integer)(w*sf);
  174.     height = (integer)(h*sf);
  175.     for (p = doc_import_list; p != NULL; p = p->next)
  176.         if (strcmp(p->file, filename) == 0)
  177.             break;
  178.     if (p == NULL) {
  179.         message(ERROR, "can't import %s", filename);
  180.         return;
  181.     }
  182.     fputs("BO /showpage {} def\n", psfp);
  183.     for (q = p->font; q != NULL; q = q->next)
  184.         if (!q->f->in_prolog)
  185.             emit_ps_font(q->f->s, psfp);
  186.     if (region != NO_REGION) {
  187.         integer ox = 0, oy = 0;
  188.         do_transform(region, &ox, &oy, psfp);
  189.         x -= ox;
  190.         y -= oy;
  191.     }
  192.     bb = p->bb;
  193.     if (bb.urx == bb.llx) {
  194.         message(ERROR, "bad bounding box: no width");
  195.         return;
  196.     }
  197.     if (bb.ury == bb.lly) {
  198.         message(ERROR, "bad bounding box: no height");
  199.         return;
  200.     }
  201.     xscale = width/(bb.urx - bb.llx);
  202.     yscale = height/(bb.ury - bb.lly);
  203.     if (xscale > yscale) {
  204.         lly = y;
  205.         ury = y - height;
  206.         gap = (integer)(width - yscale*(bb.urx - bb.llx));
  207.         switch(hadj) {
  208.         case CENTER :
  209.             llx = x + gap/2;
  210.             urx = x + width - gap/2;
  211.             break;
  212.         case LEFT :
  213.             llx = x;
  214.             urx = x + width - gap;
  215.             break;
  216.         case RIGHT :
  217.             llx = x + gap;
  218.             urx = x + width;
  219.             break;
  220.         case FILL :
  221.             llx = x;
  222.             urx = x + width;
  223.             break;
  224.         default :
  225.             cant_happen();
  226.         }
  227.     }
  228.     else {
  229.         llx = x;
  230.         urx = x + width;
  231.         gap = (integer)(height - xscale*(bb.ury - bb.lly));
  232.         switch(vadj) {
  233.         case CENTER :
  234.             lly = y - gap/2;
  235.             ury = y - height + gap/2;
  236.             break;
  237.         case TOP :
  238.             lly = y - gap;
  239.             ury = y - height;
  240.             break;
  241.         case BOTTOM :
  242.             lly = y;
  243.             ury = y - height + gap;
  244.             break;
  245.         case FILL :
  246.             lly = y;
  247.             ury = y - height;
  248.             break;
  249.         default :
  250.             cant_happen();
  251.         }
  252.     }
  253.     fprintf(psfp, "%lg %lg %lg %lg ", bb.llx, bb.lly, bb.urx, bb.ury);
  254.     
  255.     put_dim((long)llx, psfp);
  256.     putc(' ', psfp);
  257.     put_dim((long)lly, psfp);
  258.     putc(' ', psfp);
  259.     put_dim((long)urx, psfp);
  260.     putc(' ', psfp);
  261.     put_dim((long)ury, psfp);
  262.     fputs(" Locate\n", psfp);
  263.     fprintf(psfp, "%%%%BeginDocument: %s\n", filename);
  264.     if (include_file(filename, psfp) == EOF)
  265.         message(ERROR, "can't find import file %s: abandoning import",
  266.             filename);
  267.     fputs("\n%%EndDocument\nEO\n", psfp);
  268. }
  269.  
  270. /* this is called at the end of each page by eop to deal with
  271. any import specials on the current page; it calls do_import to do
  272. the real work */
  273.  
  274. void p_import_list(psfp, page)
  275. FILE *psfp;
  276. struct page_info *page;
  277. {
  278.     if (import_list == NULL)
  279.         return;
  280.     while (import_list != NULL) {
  281.         struct import *q = import_list;
  282.         do_import(import_list->arg, import_list->x, import_list->y, 
  283.                  import_list->region, page, psfp);
  284.         import_list = import_list->next;
  285.         free((char *)q);
  286.     }
  287. }
  288.  
  289.  
  290.  
  291. /* this holds a list of all the pieces of inline code for the current page */
  292.  
  293. static struct inline_code {
  294.     int region;
  295.     integer h, v;
  296.     struct inline_code *next;
  297.     char s[1];
  298. } *inline_list = NULL;
  299.  
  300. /* this is called by eop at the end of every page to emit any inline
  301. specials */
  302.  
  303. void p_inline_list(psfp)
  304. FILE *psfp;
  305. {
  306.     struct inline_code *p = NULL;
  307.     integer ox = 0, oy = 0;
  308.     int r = NO_REGION;
  309.     /* reverse the list */
  310.     if (inline_list == NULL)
  311.         return;
  312.     fputs("BO\n", psfp);
  313.     while (inline_list != NULL) {
  314.         struct inline_code *q = inline_list;
  315.         inline_list = inline_list->next;
  316.         q->next = p;
  317.         p = q;
  318.     }
  319.     while (p != NULL) {
  320.         struct inline_code *q = p;
  321.         if (p->region != r) {
  322.             fprintf(psfp, "%% region %d\n", p->region);
  323.             if (r != NO_REGION)
  324.                 fputs("grestore\n", psfp);
  325.             if (p->region != NO_REGION) {
  326.                 fputs("gsave\n", psfp);
  327.                 do_transform(p->region, &ox, &oy, psfp);
  328.             }
  329.             else
  330.                 ox = oy = 0;
  331.             r = p->region;
  332.         }
  333.         put_dim((long)(p->h-ox), psfp);
  334.         putc(' ', psfp);
  335.         put_dim((long)(p->v-oy), psfp);
  336.         fputs(" M\n", psfp);
  337.         fputs("gsave\n", psfp);
  338.         put_dim(1L, psfp);
  339.         fputs(" dup scale\n", psfp);
  340.         fputs(p->s, psfp);
  341.         putc('\n', psfp);
  342.         fputs("grestore\n", psfp);
  343.         p = p->next;
  344.         free((char *)q);
  345.     }
  346.     inline_list = NULL;
  347.     if (r != NO_REGION)
  348.         fputs("grestore\n", psfp);
  349.     fputs("EO\n", psfp);
  350. }
  351. /* this list is used during pass 1 to hold a list of all prologue files */
  352.  
  353. struct string_list {
  354.     struct string_list *next;
  355.     char s[1];
  356. };
  357.  
  358. static struct string_list *prologue_list;
  359.  
  360. /* this is called by special during pass 1 to add a prologue file to 
  361. prologue_list */
  362.  
  363.  
  364. /* this is called while the prologue is being written to include all the
  365. prologue files that have been specified in the document */
  366.  
  367. void p_special_prologues(psfp)
  368. FILE *psfp;
  369. {
  370.     while (prologue_list != NULL) {
  371.         struct string_list *temp = prologue_list;
  372.         if (include_file(prologue_list->s, psfp) == EOF)
  373.             message(ERROR, "can't open prologue file %s: ignoring it", 
  374.                     prologue_list->s);
  375.         prologue_list = prologue_list->next;
  376.         free((char *)temp);
  377.     }
  378. }
  379.  
  380. #ifdef PROTO 
  381. typedef void special_t(int pass, char *arg, integer x, integer y);
  382. static special_t landscape_special;
  383. static special_t magnification_special;
  384. static special_t prolog_special;
  385. static special_t inline_special;
  386. static special_t import_special;
  387. static special_t rotate_special;
  388. static special_t transform_special;
  389. static special_t origin_special;
  390. static special_t begin_special;
  391. static special_t end_special;
  392. static special_t form_special;
  393. static special_t hsbcolor_special;
  394. static special_t rgbcolor_special;
  395. static special_t gray_special;
  396. #else
  397. static void landscape_special();
  398. static void magnification_special();
  399. static void prolog_special();
  400. static void inline_special();
  401. static void import_special();
  402. static void rotate_special();
  403. static void transform_special();
  404. static void origin_special();
  405. static void begin_special();
  406. static void end_special();
  407. static void form_special();
  408. static void hsbcolor_special();
  409. static void rgbcolor_special();
  410. static void gray_special();
  411. #endif
  412.  
  413.  
  414. static struct {
  415.     char *name;
  416. #ifdef PROTO
  417.     special_t *proc;
  418. #else
  419.     void (*proc)();
  420. #endif
  421. } special_table[] = {
  422.     "landscape", landscape_special,
  423.     "magnification", magnification_special,
  424.     "prolog", prolog_special,
  425.     "inline", inline_special,
  426.     "import", import_special,
  427.     "rotate", rotate_special,
  428.     "transform", transform_special,
  429.     "origin", origin_special,
  430.     "begin", begin_special,
  431.     "end", end_special,
  432.     "form", form_special,
  433.     "rgbcolor", rgbcolor_special,
  434.     "hsbcolor", hsbcolor_special,
  435.     "gray", gray_special,
  436.     NULL
  437. };
  438.  
  439. static void landscape_special(pass, arg, x, y)
  440. int pass;
  441. char *arg;
  442. integer x, y;
  443. {
  444.     if (pass == PASS2)
  445.         landscape = TRUE;
  446. }
  447.  
  448. static void magnification_special(pass, arg, x, y)
  449. int pass;
  450. char *arg;
  451. integer x, y;
  452. {
  453.     if (pass == PASS2) {
  454.         int n;
  455.         n = atoi(arg);
  456.         if (n <= 0)
  457.             message(ERROR, "bad magnification");
  458.         else
  459.             magnification = n;
  460.     }
  461. }
  462.  
  463.  
  464. static void prolog_special(pass, arg, x, y)
  465. int pass;
  466. char *arg;
  467. integer x, y;
  468. {
  469.     char *p = arg;
  470.     struct string_list *ptr;
  471.     if (pass != PASS1)
  472.         return;
  473.     while (!isspace(*p) && *p != '\0')
  474.         p++;
  475.     *p = '\0';
  476.     for (ptr = prologue_list; ptr != NULL; ptr = ptr->next)
  477.         if (strcmp(arg, ptr->s) == 0)
  478.             return;
  479.     if ((ptr = (struct string_list *)
  480.             malloc(sizeof(struct string_list) + strlen(arg))) == NULL)
  481.         out_of_memory();
  482.     strcpy(ptr->s, arg);
  483.     ptr->next = prologue_list;
  484.     prologue_list = ptr;
  485. }
  486.  
  487.     
  488. static void inline_special(pass, arg, x, y)
  489. int pass;
  490. char *arg;
  491. integer x;
  492. integer y;
  493. {
  494.     struct inline_code *p;
  495.     if (pass != PASS2)
  496.         return;
  497.     p = (struct inline_code *)
  498.       malloc(sizeof(struct inline_code) + strlen(arg));
  499.     if (p == NULL)
  500.         out_of_memory();
  501.     p->h = x;
  502.     p->v = y;
  503.     p->region = current_region;
  504.     strcpy(p->s, arg);
  505.     p->next = inline_list;
  506.     inline_list = p;
  507. }
  508.  
  509.  
  510.  
  511. static void import_special(pass, arg, x, y)
  512. int pass;
  513. char *arg;
  514. integer x, y;
  515. {
  516.     if (pass == PASS2) {
  517.         struct import *p;
  518.         if ((p = (struct import *)
  519.                 malloc(sizeof(struct import)+strlen(arg))) == NULL)
  520.             out_of_memory();
  521.         p->x = x;
  522.         p->y = y;
  523.         p->region = current_region;
  524.         strcpy(p->arg, arg);
  525.         p->next = import_list;
  526.         import_list = p;
  527.     }
  528.     else
  529.         read_import_file(strtok(arg, " \n\t\r"));
  530. }
  531.         
  532. /* x and y are 0 on PASS1 */
  533.  
  534. void special(pass, s, x, y)
  535. int pass;
  536. char *s;
  537. integer x, y;
  538. {
  539.     char *q;
  540.     int i;
  541.     char *p = s;
  542.     if (pass != PASS1 && pass != PASS2)
  543.         cant_happen();
  544. #ifdef TPIC_SUPPORT
  545.     if (tpic_special(pass, s, x, y))
  546.         return;
  547. #endif
  548.     while (isspace(*p))
  549.         p++;
  550.     q = p;
  551.     while (*q != '\0' && *q != ':') {
  552.         *q = isupper(*q) ? tolower(*q) : *q;
  553.         q++;
  554.     }
  555.     if (*q == '\0') {
  556.         if (pass == PASS2)
  557.             message(WARNING, 
  558.                 "a \\special without the `dvitops:' tag was ignored");
  559.         return;
  560.     }
  561.     *q++ = '\0';
  562.     if (strcmp(p, "dvitops") != 0) {
  563.         if (pass == PASS2)
  564.             message(WARNING, 
  565.                 "a \\special without the `dvitops:' tag was ignored");
  566.         return;
  567.     }
  568.     while (isspace(*q))
  569.         q++;
  570.     p = q;
  571.     while (*q != '\0' && !isspace(*q)) {
  572.         *q = isupper(*q) ? tolower(*q) : *q;
  573.         q++;
  574.     }
  575.     if (*q != '\0')
  576.         *q++ = '\0';
  577.     for (i = 0; special_table[i].name != NULL; i++)
  578.         if (strcmp(p, special_table[i].name) == 0) {
  579.             (*special_table[i].proc)(pass, q, x, y);
  580.             return;
  581.         }
  582.     if (pass == PASS2)
  583.         message(ERROR, "\\special keyword not recognised: %s", p);
  584. }
  585.  
  586.  
  587. #ifndef M_PI
  588. #define M_PI 3.14159265358979324
  589. #endif
  590.  
  591. #define REGION_MAX 256
  592. #define RNAME_MAX 128
  593. static char *WS = " \n\r\t";
  594. /* we represent a two-dimensional transformation with the `matrix' 
  595. structure; it represents the matrix
  596. |a    b |
  597. |c    d |
  598. */
  599.  
  600. typedef struct {
  601.     double a, b, c, d;
  602. } matrix_t;
  603.  
  604.  
  605. enum color_type { NO_COLOR, RGB_COLOR, HSB_COLOR, GRAY_COLOR };
  606.  
  607. typedef struct  {
  608.     char name[RNAME_MAX];
  609.     integer origin_x;
  610.     integer origin_y;
  611.     matrix_t matrix;
  612.     enum color_type color_type;
  613.     double color[3];
  614. } region_t;
  615.  
  616. static region_t *region[REGION_MAX];
  617. #ifdef PROTO
  618. static int lookup_region(char *name);
  619. static void multiply(matrix_t *m, matrix_t *n, matrix_t *mn);
  620. #else
  621. static int lookup_region();
  622. static void multiply();
  623. #endif 
  624.  
  625. /* m, n and mn must all be distinct */
  626.  
  627. static void multiply(m, n, mn)
  628. matrix_t *m, *n, *mn;
  629. {
  630.     mn->a = m->a*n->a + m->b*n->c;
  631.     mn->b = m->a*n->b + m->b*n->d;
  632.     mn->c = m->c*n->a + m->d*n->c;
  633.     mn->d = m->c*n->b + m->d*n->d;
  634. }
  635.  
  636.  
  637. static int lookup_region(name)
  638. char *name;
  639. {
  640.     int i;
  641.     for (i = 0; i < nregions; i++) {
  642.         if (region[i] == NULL)
  643.             cant_happen();
  644.         if (strncmp(region[i]->name, name, RNAME_MAX) == 0)
  645.             return i;
  646.     }
  647.     if (nregions >= REGION_MAX)
  648.         message(FATAL_ERROR, "too many regions");
  649.     if (region[nregions] == NULL
  650.             && (region[nregions] = (region_t *)
  651.                             malloc(sizeof(region_t))) == NULL)
  652.         out_of_memory();
  653.     strncpy(region[nregions]->name, name, RNAME_MAX);
  654.     region[nregions]->origin_x = 0;
  655.     region[nregions]->origin_y = 0;
  656.     region[nregions]->matrix.a = 1.0;
  657.     region[nregions]->matrix.b = 0.0;
  658.     region[nregions]->matrix.c = 0.0;
  659.     region[nregions]->matrix.d = 1.0;
  660.     region[nregions]->color_type = NO_COLOR;
  661.     return nregions++;
  662. }
  663.  
  664.  
  665. static void rotate_special(pass, arg, x, y)
  666. int pass;
  667. char *arg;
  668. integer x, y;
  669. {
  670.     char name[128];
  671.     int n;
  672.     double theta;
  673.     matrix_t m;
  674.     matrix_t temp;
  675.     if (pass != PASS2)
  676.         return;
  677.     if (sscanf(arg, "%127s %lf", name, &theta) != 2) {
  678.         message(ERROR, "rotate \\special syntax error");
  679.         return;
  680.     }
  681.     n = lookup_region(name);
  682.     theta *= M_PI/180.0;
  683.     m.a = cos(theta);
  684.     m.b = sin(theta);
  685.     m.c = -sin(theta);
  686.     m.d = cos(theta);
  687.     multiply(&(region[n]->matrix), &m, &temp);
  688.     memcpy((char *)&(region[n]->matrix), (char *)&temp, sizeof(matrix_t));
  689. }
  690.  
  691.  
  692. static void transform_special(pass, arg, x, y)
  693. int pass;
  694. char *arg;
  695. integer x, y;
  696. {
  697.     char name[128];
  698.     int n;
  699.     matrix_t m, temp;
  700.     if (pass != PASS2)
  701.         return;
  702.     if (sscanf(arg, " %127s %lf %lf %lf %lf", name,
  703.             &m.a, &m.b, &m.c, &m.d) != 5) {
  704.         message(ERROR, "transform \\special syntax error");
  705.         return;
  706.     }
  707.     n = lookup_region(name);
  708.     multiply(&(region[n]->matrix), &m, &temp);
  709.     memcpy((char *)&(region[n]->matrix), (char *)&temp, sizeof(matrix_t));
  710. }
  711.  
  712. static void rgbcolor_special(pass, arg, x, y)
  713. int pass;
  714. char *arg;
  715. integer x, y;
  716. {
  717.     double color[3];
  718.     char name[128];
  719.     int i, n;
  720.     int bad = FALSE;
  721.     if (pass != PASS2)
  722.         return;
  723.     if (sscanf(arg, "%127s %lf %lf %lf", name, color, color + 1, color + 2)
  724.         != 4) {
  725.         message(ERROR, "rgbcolor \\special syntax error");
  726.         return;
  727.     }
  728.     n = lookup_region(name);
  729.     for (i = 0; i < 3 && !bad; i++)
  730.         if (color[i] < 0.0 || color[i] > 1.0) {
  731.             bad = TRUE;
  732.             message(ERROR, "color parameter must be between 0.0 and 1.0");
  733.         }
  734.         else
  735.             region[n]->color[i] = color[i];
  736.     region[n]->color_type = bad ? NO_COLOR : RGB_COLOR;
  737. }
  738.  
  739. static void hsbcolor_special(pass, arg, x, y)
  740. int pass;
  741. char *arg;
  742. integer x, y;
  743. {
  744.     double color[3];
  745.     char name[128];
  746.     int i, n;
  747.     int bad = FALSE;
  748.     if (pass != PASS2)
  749.         return;
  750.     if (sscanf(arg, "%127s %lf %lf %lf", name, color, color + 1, color + 2)
  751.         != 4) {
  752.         message(ERROR, "rgbcolor \\special syntax error");
  753.         return;
  754.     }
  755.     n = lookup_region(name);
  756.     for (i = 0; i < 3 && !bad; i++)
  757.         if (color[i] < 0.0 || color[i] > 1.0) {
  758.             bad = TRUE;
  759.             message(ERROR, "color parameter must be between 0.0 and 1.0");
  760.         }
  761.         else
  762.             region[n]->color[i] = color[i];
  763.     region[n]->color_type = bad ? NO_COLOR : RGB_COLOR;
  764. }
  765.  
  766. static void gray_special(pass, arg, x, y)
  767. int pass;
  768. char *arg;
  769. integer x, y;
  770. {
  771.     double gray;
  772.     char name[128];
  773.     int n;
  774.     if (pass != PASS2)
  775.         return;
  776.     if (sscanf(arg, "%127s %lf", name, &gray) != 2) {
  777.         message(ERROR, "gray \\special syntax error");
  778.         return;
  779.     }
  780.     n = lookup_region(name);
  781.     if (gray < 0.0 || gray > 1.0) {
  782.         message(ERROR, "gray parameter must be between 0.0 and 1.0");
  783.         region[n]->color_type = NO_COLOR;
  784.     }
  785.     else {
  786.         region[n]->color[0] = gray;
  787.         region[n]->color_type = GRAY_COLOR;
  788.     }
  789. }
  790.  
  791.  
  792. static void origin_special(pass, arg, x, y)
  793. int pass;
  794. char *arg;
  795. integer x, y;
  796. {
  797.     int n;
  798.     if (pass != PASS2)
  799.         return;
  800.     arg = strtok(arg, WS);
  801.     if (arg == NULL)
  802.         message(ERROR, "origin \\special syntax error");
  803.     n = lookup_region(arg);
  804.     if (region[n]->origin_x != 0 || region[n]->origin_y != 0)
  805.         message(WARNING, "multiple origins for object %s", arg);
  806.     region[n]->origin_x = x;
  807.     region[n]->origin_y = y;
  808. }
  809.  
  810.  
  811.  
  812. static void begin_special(pass, arg, x, y)
  813. int pass;
  814. char *arg;
  815. integer x, y;
  816. {
  817.     if (pass != PASS2)
  818.         return;
  819.     arg = strtok(arg, WS);
  820.     if (current_region != NO_REGION)
  821.         message(ERROR, "can't have  nested begin \\special");
  822.     current_region = lookup_region(arg);
  823. }
  824.  
  825. static void end_special(pass, arg, x, y)
  826. int pass;
  827. char *arg;
  828. integer x, y;
  829. {
  830.     if (pass != PASS2)
  831.         return;
  832.     if (current_region == NO_REGION)
  833.         message(ERROR, "end with no begin");
  834.     else
  835.         current_region = NO_REGION;
  836. }
  837.  
  838. void do_transform(n, origin_x, origin_y, psfp)
  839. int n;
  840. integer *origin_x, *origin_y;
  841. FILE *psfp;
  842. {
  843.     if (n >= nregions)
  844.         message(FATAL_ERROR, "too many regions");
  845.     *origin_x = region[n]->origin_x;
  846.     *origin_y = region[n]->origin_y;
  847.     if (*origin_x != 0 || *origin_y != 0) {
  848.         put_dim((long)*origin_x, psfp);
  849.         putc(' ', psfp);
  850.         put_dim((long)*origin_y, psfp);
  851.         fputs(" translate\n", psfp);
  852.     }
  853.     fprintf(psfp, "[%g %g %g %g 0 0] concat\n",
  854.         region[n]->matrix.a, region[n]->matrix.b,
  855.         region[n]->matrix.c, region[n]->matrix.d);
  856.     switch(region[n]->color_type) {
  857.     case GRAY_COLOR:
  858.         fprintf(psfp, "%g setgray\n", region[n]->color[0]);
  859.         break;
  860.     case RGB_COLOR:
  861.         fprintf(psfp, "%g %g %g setrgbcolor\n", region[n]->color[0],
  862.                 region[n]->color[1], region[n]->color[2]);
  863.         break;
  864.     case HSB_COLOR:
  865.         fprintf(psfp, "%g %g %g sethsbcolor\n", region[n]->color[0],
  866.                 region[n]->color[1], region[n]->color[2]);
  867.         break;
  868.     case NO_COLOR:
  869.         break;
  870.     default:
  871.         cant_happen();
  872.     }
  873. }
  874.  
  875. int strprefix(prefix, s)
  876. char *prefix, *s;
  877. {
  878.     while (*prefix != '\0')
  879.         if (*prefix++ != *s++)
  880.             return FALSE;
  881.     return TRUE;
  882. }
  883.  
  884. /* this needs rewriting */
  885.  
  886. static void read_import_file(filename)
  887. char *filename;
  888. {
  889.     FILE *fp;
  890.     char buf[256];
  891.     struct import_file *p;
  892.     struct depend_list *q;
  893.     int atend = FALSE, had_bb = FALSE, in_body = FALSE;
  894.     int in_trailer = FALSE;
  895.     p = (struct import_file *)
  896.             malloc(sizeof(struct import_file) + strlen(filename));
  897.     if (p == NULL)
  898.         out_of_memory();
  899.     strcpy(p->file, filename);
  900.     p->font = NULL;
  901.     p->next = doc_import_list;
  902.     if ((fp = xfopen(filename, FALSE, texinputs, (char *)NULL)) == NULL) {
  903.         message(ERROR, "can't open %s", filename);
  904.         return;
  905.     }
  906.     if (fgets(buf, sizeof(buf), fp) == NULL) {
  907.         message(WARNING, "empty import file %s", filename);
  908.         fclose(fp);
  909.         return;
  910.     }
  911.     if (!strprefix("%!", buf)) {
  912.         message(ERROR, "%s not PostScript: doesn't start with %%!", filename);
  913.         fclose(fp);
  914.         return;
  915.     }
  916.     if (fgets(buf, sizeof(buf), fp) == NULL) {
  917.         message(WARNING, "empty import file %s", filename);
  918.         fclose(fp);
  919.         return;
  920.     }
  921.     for (;;) {
  922.         char *k;
  923.         k = strtok(buf + 2, ": \t\r\n");
  924.         if (k == NULL || !strprefix("%%", buf) 
  925.                 || strcmp(k, "EndComments") == 0) {
  926.             if (atend) {
  927.                 in_body = TRUE;
  928.             }
  929.             else
  930.                 break;
  931.         }
  932.         else if (in_body && !in_trailer) {
  933.             if (strcmp(k, "Trailer") == 0)
  934.                 in_trailer = TRUE;
  935.         }
  936.         else if (strcmp(k, "DocumentFonts") == 0) {
  937.             for (;;) {
  938.                 struct postscript_f_list *f;
  939.                 char *ptr = strtok((char *)NULL, " \t\r\n");
  940.                 if (ptr != NULL && strcmp(ptr, "(atend)") == 0) {
  941.                     atend = TRUE;
  942.                     break;
  943.                 }
  944.                 while (ptr == NULL) {
  945.                     if (fgets(buf, sizeof(buf), fp) == NULL) {
  946.                         buf[0] = '\0';
  947.                         goto out;
  948.                     }
  949.                     if (memcmp(buf, "%%+", 3) != 0)
  950.                         goto out;
  951.                     ptr = strtok(buf+3, "\n\r\t ");
  952.                 }
  953.                 f = add_postscript_font(ptr);
  954.                 q = (struct depend_list *)malloc(sizeof(struct depend_list));
  955.                 q->f = f;
  956.                 q->next = p->font;
  957.                 p->font = q;
  958.             }
  959.             out: continue; /* don't read a line */
  960.         }
  961.         else if (strcmp(k, "BoundingBox") == 0) {
  962.             int i;
  963.             for (i = 0; i < 4; i++) {
  964.                 char *ptr = strtok((char *)NULL, "\r\t\n ");
  965.                 double x;
  966.                 if (ptr == NULL) {
  967.                     message(ERROR, "BoundingBox comment empty");
  968.                     fclose(fp);
  969.                     return;
  970.                 }
  971.                 if (i == 0 && strcmp(ptr, "(atend)") == 0) {
  972.                     atend = TRUE;
  973.                     break;
  974.                 }
  975.                 had_bb = TRUE;
  976.                 x = atof(ptr);
  977.                 switch(i) {
  978.                 case 0:
  979.                     p->bb.llx = x;
  980.                     break;
  981.                 case 1:
  982.                     p->bb.lly = x;
  983.                     break;
  984.                 case 2:
  985.                     p->bb.urx = x;
  986.                     break;
  987.                 case 3:
  988.                     p->bb.ury = x;
  989.                     break;
  990.                 default:
  991.                     cant_happen();
  992.                 }
  993.             }
  994.         }
  995.         if (fgets(buf, sizeof(buf), fp) == NULL)
  996.             break;
  997.     }
  998.     if (!had_bb) {
  999.         message(ERROR, "%s: no BoundingBox comment", filename);
  1000.         fclose(fp);
  1001.         return;
  1002.     }
  1003.     doc_import_list = p;
  1004.     fclose(fp);
  1005. }
  1006.  
  1007. static struct string_list *form_list;
  1008.  
  1009. static void form_special(pass, arg, x, y)
  1010. int pass;
  1011. char *arg;
  1012. integer x;
  1013. integer y;
  1014. {
  1015.     struct string_list *s;
  1016.     if (pass != PASS2)
  1017.         return;
  1018.     if ((s = (struct string_list *)malloc(sizeof(struct string_list) + strlen(arg))) == NULL)
  1019.         out_of_memory();
  1020.     s->next = form_list;
  1021.     form_list = s;
  1022.     strcpy(s->s, arg);
  1023. }
  1024.  
  1025. void p_form_list(psfp)
  1026. FILE *psfp;
  1027. {
  1028.     while (form_list != NULL) {
  1029.         struct string_list *s = form_list;
  1030.         fputs("/showpage {} def\n", psfp);
  1031.         fprintf(psfp, "/--save-- save def\n%%%%BeginDocument: %s\n", s->s);
  1032.         if (include_file(s->s, psfp) == EOF)
  1033.             message(ERROR, "can't find %s", s->s);
  1034.         fputs("\n%%EndDocument\n--save-- restore\n", psfp);
  1035.         form_list = s->next;
  1036.         free((char *)s);
  1037.     }
  1038. }
  1039.  
  1040. /*
  1041. Local Variables:
  1042. c-indent-level: 4
  1043. c-continued-statement-offset: 4
  1044. c-brace-offset: -4
  1045. c-argdecl-indent: 0
  1046. c-label-offset: -4
  1047. tab-width: 4
  1048. End:
  1049. */
  1050.  
  1051.